﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml;
using XmlStudio.DataLayer;
using XmlStudio.Interfaces;
using XmlStudio.Models.Events;
using XmlStudio.Utilities;
using XmlStudio.Enums;

namespace XmlStudio.Models.Actions {
    /// <summary>
    /// Removes specified node from its parent.
    /// </summary>
    internal sealed class RemoveNodeAction : XmlModelAction {
        #region Fields
        #region Private
        /// <summary>
        /// Node to remove.
        /// </summary>
        private BigXmlNodeInternal nodeToRemove;

        /// <summary>
        /// Parent node of the node to remove.
        /// </summary>
        private BigXmlNodeInternal parentNode;

        private BigXmlNodeInternal referenceNode;

        private XmlNode xmlNodeToRemove;

        private InsertMode insertMode = InsertMode.First;
        #endregion
        #endregion

        #region Constructors
        #region Public
        /// <summary>
        /// Initializes a new instance of the <see cref="RemoveNodeAction"/> class.
        /// </summary>
        /// <param name="model">XmlModel to use.</param>
        /// <param name="nodeToRemove">Node to remove.</param>
        public RemoveNodeAction(IXmlModelWithNotifications model, BigXmlNodeInternal nodeToRemove)
            : base(model) {
            this.nodeToRemove = nodeToRemove;
            this.xmlNodeToRemove = this.nodeToRemove.XmlNode;
            this.parentNode = this.nodeToRemove.Parent as BigXmlNodeInternal;
            if(this.parentNode != null) {
                this.referenceNode = this.parentNode.GetLeftSibling(this.nodeToRemove) as BigXmlNodeInternal;
                this.insertMode = InsertMode.After;
                if(this.referenceNode == null) {
                    this.insertMode = InsertMode.First;
                }
            }

            if(this.parentNode != null) {
                this.wasModified = this.parentNode.Modified;
            } else {
                this.wasModified = this.nodeToRemove.Modified;
            }

            this.address = nodeToRemove.Address.DeepClone<int[]>();
        }
        #endregion
        #endregion

        #region Methods
        #region Protected
        /// <summary>
        /// Executes the action.
        /// </summary>
        protected override void ExecuteCore() {
            if(this.parentNode != null) {
                this.parentNode.XmlNode.RemoveChild(this.xmlNodeToRemove);
                this.parentNode.ChildNodes.Remove(this.nodeToRemove);
                TreeBuilder.AdjustAddresses(this.parentNode, this.model);
                this.nodeToRemove.SetParent(null);
                this.parentNode.SetModified(true);
                this.model.TotalNodeCount--;
            } else {
                this.model.Root = null;
                this.model.RemoveRootNode();
                this.model.TotalNodeCount--;
            }

            this.model.RemoveNodeWithChildren(nodeToRemove.XmlNode);

            this.model.SetModified(true);
            this.model.OnNodeRemoved(new NodeRemovedEventArgs<BigXmlNode>(nodeToRemove));
            this.model.OnRawXmlChanged(new RawXmlChangedEventArgs());
        }

        /// <summary>
        /// Executes the undo for the current action.
        /// </summary>
        protected override void UnExecuteCore() {
            //if(parentNode != null) {
            var action = new AddChildNodeAction(this.model, this.parentNode, this.nodeToRemove, this.insertMode, this.referenceNode);
            action.Execute();

            if(this.parentNode != null) {
                this.parentNode.SetModified(this.wasModified);
            }
            //} else {
            //    var action = new CreateRootElementAction(this.xmlModel, this.nodeToRemove.Prefix, this.nodeToRemove.LocalName, this.nodeToRemove.NamespaceURI);
            //    action.Execute();
            //}                        
        }
        #endregion
        #endregion
    }
}